local Gladius = _G.Gladius
if not Gladius then
	DEFAULT_CHAT_FRAME:AddMessage(format("Module %s requires Gladius", "Health Bar"))
end
local L = Gladius.L
local LSM

-- global functions
local strfind = string.find
local pairs = pairs
local UnitHealth, UnitHealthMax, UnitClass = UnitHealth, UnitHealthMax, UnitClass

local HealthBar = Gladius:NewModule("HealthBar", true, true, {
	healthBarAttachTo = "Frame",
	healthBarHeight = 25,
	healthBarAdjustWidth = true,
	healthBarWidth = 200,
	healthBarInverse = false,
	healthBarColor = {r = 1, g = 1, b = 1, a = 1},
	healthBarClassColor = true,
	healthBarBackgroundColor = {r = 1, g = 1, b = 1, a = 0.3},
	healthBarTexture = "minimalist",
	healthBarOffsetX = 0,
	healthBarOffsetY = 0,
	healthBarAnchor = "TOPLEFT",
	healthBarRelativePoint = "TOPLEFT",
	healthBarUseDefaultColorPriest = true,
	healthBarColorPriest = RAID_CLASS_COLORS["PRIEST"],
	healthBarUseDefaultColorPaladin = true,
	healthBarColorPaladin = RAID_CLASS_COLORS["PALADIN"],
	healthBarUseDefaultColorShaman = true,
	healthBarColorShaman = RAID_CLASS_COLORS["SHAMAN"],
	healthBarUseDefaultColorDruid = true,
	healthBarColorDruid = RAID_CLASS_COLORS["DRUID"],
	healthBarUseDefaultColorMage = true,
	healthBarColorMage = RAID_CLASS_COLORS["MAGE"],
	healthBarUseDefaultColorWarlock = true,
	healthBarColorWarlock = RAID_CLASS_COLORS["WARLOCK"],
	healthBarUseDefaultColorHunter = true,
	healthBarColorHunter = RAID_CLASS_COLORS["HUNTER"],
	healthBarUseDefaultColorWarrior = true,
	healthBarColorWarrior = RAID_CLASS_COLORS["WARRIOR"],
	healthBarUseDefaultColorRogue = true,
	healthBarColorRogue = RAID_CLASS_COLORS["ROGUE"],
	healthBarUseDefaultColorDeathknight = true,
	healthBarColorDeathknight = RAID_CLASS_COLORS["DEATHKNIGHT"],
})

function HealthBar:OnEnable()
	self:RegisterEvent("UNIT_HEALTH")
	self:RegisterEvent("UNIT_MAXHEALTH", "UNIT_HEALTH")
	LSM = Gladius.LSM
	-- set frame type
	if (Gladius.db.healthBarAttachTo == "Frame" or strfind(Gladius.db.healthBarRelativePoint, "BOTTOM")) then
		self.isBar = true
	else
		self.isBar = false
	end
	if (not self.frame) then
		self.frame = { }
	end
end

function HealthBar:OnDisable()
	self:UnregisterAllEvents()
	for unit in pairs(self.frame) do
		self.frame[unit]:SetAlpha(0)
	end
end

function HealthBar:GetAttachTo()
	return Gladius.db.healthBarAttachTo
end

function HealthBar:GetFrame(unit)
	return self.frame[unit]
end

function HealthBar:UNIT_HEALTH(event, unit)
	if (not strfind(unit, "arena") or strfind(unit, "pet")) then
		return
	end
	local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
	self:UpdateHealth(unit, health, maxHealth)
end

function HealthBar:UpdateHealth(unit, health, maxHealth)
	if (not self.frame[unit]) then
		if (not Gladius.buttons[unit]) then
			Gladius:UpdateUnit(unit)
		else
			self:Update(unit)
		end
	end
	-- update min max values
	if (self.frame[unit] == nil) then
		return
	end
	self.frame[unit]:SetMinMaxValues(0, maxHealth)
	-- inverse bar
	if (Gladius.db.healthBarInverse) then
		self.frame[unit]:SetValue(maxHealth - health)
	else
		self.frame[unit]:SetValue(health)
	end
end

function HealthBar:CreateBar(unit)
	local button = Gladius.buttons[unit]
	if (not button) then
		return
	end
	-- create bar + text
	self.frame[unit] = CreateFrame("STATUSBAR", "Gladius"..self.name..unit, button) 
	self.frame[unit].background = self.frame[unit]:CreateTexture("Gladius"..self.name..unit.."Background", "BACKGROUND")
	self.frame[unit].highlight = self.frame[unit]:CreateTexture("Gladius"..self.name.."Highlight"..unit, "OVERLAY")
end

function HealthBar:Update(unit)
	-- check parent module
	if (not Gladius:GetModule(Gladius.db.castBarAttachTo)) then
		if (self.frame[unit]) then
			self.frame[unit]:Hide()
		end
		return
	end
	-- create power bar
	if (not self.frame[unit]) then
		self:CreateBar(unit)
	end
	-- set bar type 
	local parent = Gladius:GetParent(unit, Gladius.db.healthBarAttachTo)
	if (Gladius.db.healthBarAttachTo == "Frame" or strfind(Gladius.db.healthBarRelativePoint, "BOTTOM")) then
		self.isBar = true
	else
		self.isBar = false
	end
	-- update health bar
	self.frame[unit]:ClearAllPoints()
	local width = Gladius.db.healthBarAdjustWidth and Gladius.db.barWidth or Gladius.db.healthBarWidth
	-- add width of the widget if attached to an widget
	if (Gladius.db.healthBarAttachTo ~= "Frame" and not strfind(Gladius.db.healthBarRelativePoint,"BOTTOM") and Gladius.db.healthBarAdjustWidth) then
		if (not Gladius:GetModule(Gladius.db.healthBarAttachTo).frame[unit]) then
			Gladius:GetModule(Gladius.db.healthBarAttachTo):Update(unit)
		end
		width = width + Gladius:GetModule(Gladius.db.healthBarAttachTo).frame[unit]:GetWidth()
	end
	self.frame[unit]:SetHeight(Gladius.db.healthBarHeight)
	self.frame[unit]:SetWidth(width) 
	self.frame[unit]:SetPoint(Gladius.db.healthBarAnchor, parent, Gladius.db.healthBarRelativePoint, Gladius.db.healthBarOffsetX, Gladius.db.healthBarOffsetY)
	self.frame[unit]:SetMinMaxValues(0, 100)
	self.frame[unit]:SetValue(100)
	self.frame[unit]:SetStatusBarTexture(LSM:Fetch(LSM.MediaType.STATUSBAR, Gladius.db.healthBarTexture))
	-- disable tileing
	self.frame[unit]:GetStatusBarTexture():SetHorizTile(false)
	self.frame[unit]:GetStatusBarTexture():SetVertTile(false)
	-- update health bar background
	self.frame[unit].background:ClearAllPoints()
	self.frame[unit].background:SetAllPoints(self.frame[unit])
	self.frame[unit].background:SetWidth(self.frame[unit]:GetWidth())
	self.frame[unit].background:SetHeight(self.frame[unit]:GetHeight())	
	self.frame[unit].background:SetTexture(LSM:Fetch(LSM.MediaType.STATUSBAR, Gladius.db.healthBarTexture))
	self.frame[unit].background:SetVertexColor(Gladius.db.healthBarBackgroundColor.r, Gladius.db.healthBarBackgroundColor.g, Gladius.db.healthBarBackgroundColor.b, Gladius.db.healthBarBackgroundColor.a)
	-- disable tileing
	self.frame[unit].background:SetHorizTile(false)
	self.frame[unit].background:SetVertTile(false)
	-- update highlight texture
	self.frame[unit].highlight:SetAllPoints(self.frame[unit])
	self.frame[unit].highlight:SetTexture([=[Interface\QuestFrame\UI-QuestTitleHighlight]=])
	self.frame[unit].highlight:SetBlendMode("ADD")
	self.frame[unit].highlight:SetVertexColor(1.0, 1.0, 1.0, 1.0)
	self.frame[unit].highlight:SetAlpha(0)
	-- hide frame
	self.frame[unit]:SetAlpha(0)
end

function HealthBar:GetBarColor(class)
	if (class == "PRIEST" and not Gladius.db.healthBarUseDefaultColorPriest) then
		return Gladius.db.healthBarColorPriest
	elseif (class == "PALADIN" and not Gladius.db.healthBarUseDefaultColorPaladin) then
		return Gladius.db.healthBarUseDefaultColorPaladin
	elseif (class == "SHAMAN" and not Gladius.db.healthBarUseDefaultColorShaman) then
		return Gladius.db.healthBarColorShaman
	elseif (class == "DRUID" and not Gladius.db.healthBarUseDefaultColorDruid) then
		return Gladius.db.healthBarColorDruid
	elseif (class == "MAGE" and not Gladius.db.healthBarUseDefaultColorMage) then
		return Gladius.db.healthBarColorMage
	elseif (class == "WARLOCK" and not Gladius.db.healthBarUseDefaultColorWarlock) then
		return Gladius.db.healthBarColorWarlock
	elseif (class == "HUNTER" and not Gladius.db.healthBarUseDefaultColorHunter) then
		return Gladius.db.healthBarColorHunter
	elseif (class == "WARRIOR" and not Gladius.db.healthBarUseDefaultColorWarrior) then
		return Gladius.db.healthBarColorWarrior
	elseif (class == "ROGUE" and not Gladius.db.healthBarUseDefaultColorRogue) then
		return Gladius.db.healthBarColorRogue
	elseif (class == "DEATHKNIGHT" and not Gladius.db.healthBarUseDefaultColorDeathknight) then
		return Gladius.db.healthBarColorDeathknight
	end
	return RAID_CLASS_COLORS[class]
end

function HealthBar:Show(unit)
	local testing = Gladius.test
	-- show frame
	self.frame[unit]:SetAlpha(1)
	-- get unit class
	local class
	if (not testing) then
		class = select(2, UnitClass(unit))
	else
		class = Gladius.testing[unit].unitClass
	end
	-- set color
	if (not Gladius.db.healthBarClassColor) then
		local color = Gladius.db.healthBarColor
		self.frame[unit]:SetStatusBarColor(color.r, color.g, color.b, color.a)
	else
		local color = self:GetBarColor(class)
		self.frame[unit]:SetStatusBarColor(color.r, color.g, color.b, color.a or 1)
	end
	-- call event
	if (not Gladius.test) then
		self:UNIT_HEALTH("UNIT_HEALTH", unit)
	end
end

function HealthBar:Reset(unit)
	if (not self.frame[unit]) then
		return
	end
	-- reset bar
	self.frame[unit]:SetMinMaxValues(0, 1)
	self.frame[unit]:SetValue(1)
	-- hide
	self.frame[unit]:SetAlpha(0)
end

function HealthBar:Test(unit)
	-- set test values
	local maxHealth = Gladius.testing[unit].maxHealth
	local health = Gladius.testing[unit].health
	self:UpdateHealth(unit, health, maxHealth)
end

function HealthBar:GetOptions()
	return {
		general = {
			type = "group",
			name = L["General"],
			order = 1,
			args = {
				bar = {
					type = "group",
					name = L["Bar"],
					desc = L["Bar settings"],
					inline = true,
					order = 1,
					args = {
						healthBarClassColor = {
							type = "toggle",
							name = L["Health bar class color"],
							desc = L["Toggle health bar class color"],
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							order = 5,
						},
						sep = {
							type = "description",
							name = "",
							width = "full",
							hidden = function()
								return not Gladius.db.advancedOptions
							end,
							order = 7,
						},
						healthBarColor = {
							type = "color",
							name = L["Health bar color"],
							desc = L["Color of the health bar"],
							hasAlpha = true,
							get = function(info)
								return Gladius:GetColorOption(info)
							end,
							set = function(info, r, g, b, a)
								return Gladius:SetColorOption(info, r, g, b, a)
							end,
							disabled = function()
								return Gladius.dbi.profile.healthBarClassColor or not Gladius.dbi.profile.modules[self.name]
							end,
							order = 10,
						},
						healthBarBackgroundColor = {
							type = "color",
							name = L["Health bar background color"],
							desc = L["Color of the health bar background"],
							hasAlpha = true,
							get = function(info)
								return Gladius:GetColorOption(info)
							end,
							set = function(info, r, g, b, a)
								return Gladius:SetColorOption(info, r, g, b, a)
							end,
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							hidden = function()
								return not Gladius.db.advancedOptions
							end,
							order = 15,
						},
						sep2 = {
							type = "description",
							name = "",
							width = "full",
							order = 17,
						},
						healthBarInverse = {
							type = "toggle",
							name = L["Health bar inverse"],
							desc = L["Inverse the health bar"],
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							hidden = function()
								return not Gladius.db.advancedOptions
							end,
							order = 20,
						},
						healthBarTexture = {
							type = "select",
							name = L["Health bar texture"],
							desc = L["Texture of the health bar"],
							dialogControl = "LSM30_Statusbar",
							values = AceGUIWidgetLSMlists.statusbar,
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							order = 25,
						},
					},
				},
				size = {
					type = "group",
					name = L["Size"],
					desc = L["Size settings"],
					inline = true,
					order = 2,
					args = {
						healthBarAdjustWidth = {
							type = "toggle",
							name = L["Health bar adjust width"],
							desc = L["Adjust health bar width to the frame width"],
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							order = 5,
						},
						sep = {
							type = "description",
							name = "",
							width = "full",
							order = 13,
						},
						healthBarWidth = {
							type = "range",
							name = L["Health bar width"],
							desc = L["Width of the health bar"],
							min = 10, max = 500, step = 1,
							disabled = function()
								return Gladius.dbi.profile.healthBarAdjustWidth or not Gladius.dbi.profile.modules[self.name]
							end,
							order = 15,
						},
						healthBarHeight = {
							type = "range",
							name = L["Health bar height"],
							desc = L["Height of the health bar"],
							min = 10, max = 200, step = 1,
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							order = 20,
						},
					},
				},
				position = {
					type = "group",
					name = L["Position"],
					desc = L["Position settings"],
					inline = true, 
					hidden = function()
						return not Gladius.db.advancedOptions
					end,
					order = 3,
					args = {
						healthBarAttachTo = {
							type = "select",
							name = L["Health Bar Attach To"],
							desc = L["Attach health bar to the given frame"],
							values = function()
								return Gladius:GetModules(self.name)
							end,
							set = function(info, value)
							local key = info.arg or info[#info]
								if (strfind(Gladius.db.healthBarRelativePoint, "BOTTOM")) then
									self.isBar = true
								else
									self.isBar = false
								end
								Gladius.dbi.profile[key] = value
								Gladius:UpdateFrame()
							end,
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							width = "double",
							order = 5,
						},
						sep = {
							type = "description",
							name = "",
							width = "full",
							order = 7,
						},
						healthBarAnchor = {
							type = "select",
							name = L["Health Bar Anchor"],
							desc = L["Anchor of the health bar"],
							values = function()
								return Gladius:GetPositions()
							end,
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							order = 10,
						},
						healthBarRelativePoint = {
							type = "select",
							name = L["Health Bar Relative Point"],
							desc = L["Relative point of the health bar"],
							values = function()
								return Gladius:GetPositions()
							end,
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							order = 15,
						},
						sep2 = {
							type = "description",
							name = "",
							width = "full",
							order = 17,
						},
						healthBarOffsetX = {
							type = "range",
							name = L["Health bar offset X"],
							desc = L["X offset of the health bar"],
							min = - 100, max = 100, step = 1,
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							order = 20,
						},
						healthBarOffsetY = {
							type = "range",
							name = L["Health bar offset Y"],
							desc = L["Y offset of the health bar"],
							disabled = function()
								return not Gladius.dbi.profile.modules[self.name]
							end,
							min = - 100, max = 100, step = 1,
							order = 25,
						},
					},
				},
			},
		},
		healthDefaultColors = {
			type = "group",
			name = L["Health colors"],
			hidden = function()
				return not Gladius.db.advancedOptions
			end,
			order = 2,
			args = {
				healthBarUseDefaultColorPriest = {
					type = "toggle",
					name = L["Default priest color"],
					desc = L["Toggle default priest color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 0,
				},
				healthBarColorPriest = {
					type = "color",
					name = L["Priest color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 5,
				},
				sep = {
					type = "description",
					name = "",
					width = "full",
					order = 7,
				},
				healthBarUseDefaultColorPaladin = {
					type = "toggle",
					name = L["Default paladin color"],
					desc = L["Toggle default paladin color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 10,
				},
				healthBarColorPaladin = {
					type = "color",
					name = L["Paladin color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 15,
				},
				sep2 = {
					type = "description",
					name = "",
					width = "full",
					order = 17,
				},
				healthBarUseDefaultColorShaman = {
					type = "toggle",
					name = L["Default shaman color"],
					desc = L["Toggle default shaman color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 20,
				},
				healthBarColorShaman = {
					type = "color",
					name = L["Shaman color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 25,
				},
				sep3 = {
					type = "description",
					name = "",
					width = "full",
					order = 27,
				},
				healthBarUseDefaultColorDruid = {
					type = "toggle",
					name = L["Default druid color"],
					desc = L["Toggle default druid color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 30,
				},
				healthBarColorDruid = {
					type = "color",
					name = L["Druid color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 35,
				},
				sep4 = {
					type = "description",
					name = "",
					width = "full",
					order = 37,
				},
				healthBarUseDefaultColorMage = {
					type = "toggle",
					name = L["Default mage color"],
					desc = L["Toggle default mage color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 40,
				},
				healthBarColorMage = {
					type = "color",
					name = L["Mage color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 45,
				},
				sep5 = {
					type = "description",
					name = "",
					width = "full",
					order = 47,
				},
				healthBarUseDefaultColorWarlock = {
					type = "toggle",
					name = L["Default warlock color"],
					desc = L["Toggle default warlock color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 50,
				},
				healthBarColorWarlock = {
					type = "color",
					name = L["Warlock color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 55,
				},
				sep6 = {
					type = "description",
					name = "",
					width = "full",
					order = 57,
				},
				healthBarUseDefaultColorHunter = {
					type = "toggle",
					name = L["Default hunter color"],
					desc = L["Toggle default hunter color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 60,
				},
				healthBarColorHunter = {
					type = "color",
					name = L["Hunter color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 65,
				},
				sep7 = {
					type = "description",
					name = "",
					width = "full",
					order = 67,
				},
				healthBarUseDefaultColorWarrior = {
					type = "toggle",
					name = L["Default warrior color"],
					desc = L["Toggle default warrior color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 70,
				},
				healthBarColorWarrior = {
					type = "color",
					name = L["Warrior color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 75,
				},
				sep8 = {
					type = "description",
					name = "",
					width = "full",
					order = 77,
				},
				healthBarUseDefaultColorRogue = {
					type = "toggle",
					name = L["Default rogue color"],
					desc = L["Toggle default eogue color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 80,
				},
				healthBarColorRogue = {
					type = "color",
					name = L["Rogue color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 85,
				},
				sep9 = {
					type = "description",
					name = "",
					width = "full",
					order = 87,
				},
				healthBarUseDefaultColorDeathknight = {
					type = "toggle",
					name = L["Default death knight color"],
					desc = L["Toggle default death knight color"],
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 90,
				},
				healthBarColorDeathknight = {
					type = "color",
					name = L["Death knight color"],
					get = function(info)
						return Gladius:GetColorOption(info)
					end,
					set = function(info, r, g, b, a)
						return Gladius:SetColorOption(info, r, g, b, 1)
					end,
					disabled = function()
						return not Gladius.dbi.profile.modules[self.name]
					end,
					order = 95,
				},
			},
		},
	}
end